package com.moyun.controller.bpm;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.moyun.common.annotation.OperLog;
import com.moyun.common.aspect.BusinessType;
import com.moyun.model.common.R;
import com.moyun.model.dto.bpm.ProcessDTO;
import com.moyun.model.po.bpm.BpmInsDocument;
import com.moyun.model.po.bpm.BpmInsRemark;
import com.moyun.model.po.bpm.BpmProcess;
import com.moyun.model.po.bpm.BpmProcessNode;
import com.moyun.model.po.system.SysUserEntity;
import com.moyun.service.bpm.BpmInsDocumentService;
import com.moyun.service.bpm.BpmInsRemarkService;
import com.moyun.service.bpm.BpmProcessNodeService;
import com.moyun.service.bpm.BpmProcessService;
import com.moyun.syssecurity.util.SecurityUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h3>moyun-base</h3>
 * <p>流程引擎服务控制层</p>
 *
 * @author : ybx
 * @date : 2021-08-25 15:41:32
 **/
@Api(tags = "业务流程")
@RestController
@RequestMapping("/wf")
@RequiredArgsConstructor
public class WorkFlowController {
    /**
     * 1.流程实例对象 服务层
     * 2.流程对象 服务层
     * 3.审批记录对象 服务层
     */
    private final BpmInsDocumentService bpmInsDocumentService;
    private final BpmProcessService bpmProcessService;
    private final BpmInsRemarkService bpmInsRemarkService;
    private final BpmProcessNodeService bpmProcessNodeService;

    @ApiOperation("流程提交")
    @PostMapping(value = "/submit-process")
    @OperLog(operModul = "工作流模块", operType = BusinessType.OTHER, operDesc = "流程实例提交")
    public R submitProcess(@RequestBody ProcessDTO processDto) {
        // 获取当前登录用户
        SysUserEntity loginUser = SecurityUtil.getLoginUser();
        /**
         * 1.定义一个流程实例对象
         * 2.定义一个流程节点对象
         * 3.流程下的节点列表
         * 4.定义一个流程对象
         **/
        BpmInsDocument bpmInsDocument;
        BpmProcessNode bpmProcessNode;
        List<BpmProcessNode> nodeList;
        BpmProcess bpmProcess;
        String currentNodeId;
        String currentUserid;
        String[] currentNodePartUserIds;


        if (StringUtils.isEmpty(processDto.getProcessId())) {
            return R.error("processId不能为空");
        }

        bpmProcess = this.bpmProcessService.getOneById(processDto.getProcessId());
        nodeList = bpmProcess.getNodeList();

        // 获取流程实例(文档)信息
        if (StringUtils.isEmpty(processDto.getDocumentId())) {
            // 1.证明是发起流程
            // 1.1 随机生成一个32位uuid 并赋值给 processDto对象
            processDto.setDocumentId(IdUtil.simpleUUID());
            // 1.2 生成一个流程实例(文档)对象,并设置相应属性
            bpmInsDocument = new BpmInsDocument().setFkProcess(processDto.getProcessId())
                    .setId(processDto.getDocumentId())
                    .setAddUserid(loginUser.getUsername())
                    .setCurrentUserid(loginUser.getUsername());
            // 1.3 根据流程id查询流程的相关信息(如: 对应的节点及节点类型)
            bpmProcessNode = nodeList.get(0);
            String nodePartUserid = bpmProcessNode.getNodePartUserid();
            String nodePartUsername = bpmProcessNode.getNodePartUsername();
            String nodeId = bpmProcessNode.getId();
            String nodeName = bpmProcessNode.getNodeName();
            // 1.4 补充bpmInsDocument信息
            bpmInsDocument.setCurrentNodeId(nodeId)
                    .setCurrentUserid(nodePartUserid)
                    .setCurrentNodeName(nodeName);
            // 1.5 入库
            this.bpmInsDocumentService.save(bpmInsDocument);
        } else {
            // 2.根据 流程id 和 实例id 去数据库中查询对应的记录
            bpmInsDocument = this.bpmInsDocumentService.getOne(new QueryWrapper<BpmInsDocument>().eq("id", processDto.getDocumentId()).eq("fk_process", processDto.getProcessId()));
            bpmProcessNode = this.bpmProcessNodeService.getOne(new QueryWrapper<BpmProcessNode>().eq("id", bpmInsDocument.getCurrentNodeId()));
        }

        currentNodeId = bpmInsDocument.getCurrentNodeId();
        currentUserid = bpmInsDocument.getCurrentUserid();
        currentNodePartUserIds = currentUserid.split(",");


        // 判断当前登录用户是否在 当前人员的处理列表中
        boolean flag = Arrays.stream(currentNodePartUserIds).anyMatch(currentPartUserId -> loginUser.getUsername().equals(currentPartUserId));
        if (!flag) {
            return R.error("当前用户没有审批权限");
        }
        // 同意
        extracted(processDto, loginUser, bpmInsDocument, currentNodeId, currentNodePartUserIds);

        // 6. 判断当前该用户是否为当前节点 最后一个完成审批的人 , 如果是,更新流程实例状态
        // 判断条件: documentId、currentNodeId、processing_type="同意" 记录数== 当前节点处理人员人数
        List<BpmInsRemark> list = this.bpmInsRemarkService.list(new QueryWrapper<BpmInsRemark>().eq("fk_document", bpmInsDocument.getId()).eq("fk_node_id", bpmInsDocument.getCurrentNodeId()));//.eq("processing_type", "同意"));
        List<Integer> collect1 = list.stream().collect(Collectors.groupingBy(BpmInsRemark::getUserid)).entrySet().stream().map(entry -> entry.getValue().size()).collect(Collectors.toList());

        if (collect1.stream().distinct().count() != 1) {

            // 等待当前节点的其他人员完成审批
            return R.ok("流程提交成功,等待当前节点剩余人员审批");
        } else {

            // 交给下一节点的人员进行审批
            List<BpmProcessNode> collect = nodeList.stream().filter(s -> Convert.toInt(s.getNodeIndex()) > Convert.toInt(bpmProcessNode.getNodeIndex())).collect(Collectors.toList());
            if (collect.size() > 0) {
                // 证明现在不是最后一个节点
                BpmProcessNode bpmProcessNodeNext = collect.get(0);
                String nodePartUserid = bpmProcessNodeNext.getNodePartUserid();
                String nodePartUsername = bpmProcessNodeNext.getNodePartUsername();
                String nodeId = bpmProcessNodeNext.getId();
                String nodeName = bpmProcessNodeNext.getNodeName();
                // 3.3 补充bpmInsDocument信息
                bpmInsDocument.setCurrentNodeId(nodeId)
                        .setCurrentUserid(String.valueOf(nodePartUserid))
                        .setCurrentNodeName(nodeName);
                this.bpmInsDocumentService.saveOrUpdate(bpmInsDocument);
                return R.ok("流程提交成功,到达下一节点:  " + nodeName);
            } else {
                this.bpmInsDocumentService.saveOrUpdate(bpmInsDocument.setEndUserid("结束了"));
                return R.ok("流程结束");
            }
        }
    }

    @ApiOperation("我的待办")
    @GetMapping(value = "/get-todoList")
    @OperLog(operModul = "工作流模块", operType = BusinessType.OTHER, operDesc = "获取我的待办")
    public R getToDoList() {

        // 获取当前登录人的信息
        SysUserEntity loginUser = SecurityUtil.getLoginUser();
        String userId = loginUser.getUsername();

        List<BpmInsDocument> documentsTemp = this.bpmInsDocumentService.list();
        // 筛选出当前用户的文档集合
        List<BpmInsDocument> documents = documentsTemp.stream().filter(document -> {
            String currentUserid = document.getCurrentUserid();
            List<String> userIds = Arrays.stream(currentUserid.split(",")).collect(Collectors.toList());
            return userIds.contains(userId);
        }).collect(Collectors.toList());

        return R.ok(documents);
    }


    @ApiOperation("我的已办")
    @RequestMapping(value = "/get-doneList", method = RequestMethod.POST)
    @OperLog(operModul = "工作流模块", operType = BusinessType.OTHER, operDesc = "流程实例提交")
    public R getDoneList(@RequestBody ProcessDTO processDto) {
        // 获取当前登录人的信息
        SysUserEntity loginUser = SecurityUtil.getLoginUser();
        String userId = loginUser.getUsername();

        List<BpmInsRemark> bpmInsRemarks = this.bpmInsRemarkService.list(new QueryWrapper<BpmInsRemark>().eq("userid", userId));
        List<String> documentIds = bpmInsRemarks.stream().map(BpmInsRemark::getFkDocument).distinct().collect(Collectors.toList());
        List<BpmInsDocument> documents = this.bpmInsDocumentService.list(new QueryWrapper<BpmInsDocument>().in("id", documentIds));

        return R.ok(documents);
    }

    private void extracted(ProcessDTO processDto, SysUserEntity loginUser, BpmInsDocument bpmInsDocument, String currentNodeId, String[] currentNodePartUserIds) {

        //5. 为当前登录用户生成一条审批记录 即 bpm_ins_remark
        // bpm_ins_remark表中 fk_document 、fk_node_id、 userid、 processing_type= 同意 记录只有一条 暂不需要此需求
        BpmInsRemark bpmInsRemark = new BpmInsRemark().setRemark(processDto.getRemark())
                .setFkDocument(bpmInsDocument.getId())
                .setFkNodeId(currentNodeId)
                .setFkNodeName("")
                .setProcessingType("同意")
                .setUserid(loginUser.getUsername())
                .setUserName(loginUser.getUsername());
        this.bpmInsRemarkService.save(bpmInsRemark);
    }


}
